#pragma once

#include <boost/coroutine2/all.hpp>
#include "NetStream.h"

class Coroutine : public std::enable_shared_from_this<Coroutine>
{
public:
    struct RPCInvokeResp {
        INetStream *pck;
        int32 err;
        bool eof;
    };
    class YieldContext {
    friend Coroutine;
    public:
        YieldContext(Coroutine &coroutine,
            boost::coroutines2::coroutine<void>::pull_type &yield);
        std::function<void(INetStream&, int32, bool)> GetRPCInvokeCb();
        const RPCInvokeResp &WaitRPCInvokeResp();
    private:
        Coroutine &coroutine_;
        boost::coroutines2::coroutine<void>::pull_type &yield_;
        union {
            const RPCInvokeResp *rpc_invoke_resp_;
        };
    };

    Coroutine(const std::function<void(YieldContext&)> &func);
    ~Coroutine();

    static void Spawn(const std::function<void(YieldContext&)> &func);

private:
    void OnRPCInvokeResp(INetStream &pck, int32 err, bool eof);

    YieldContext *context_;
    boost::coroutines2::coroutine<void>::push_type *executor_;
};
